home *** CD-ROM | disk | FTP | other *** search
/ Nothing but Tetris / Nothing but Tetris.iso / amiga / workbench_tris / main.c < prev    next >
C/C++ Source or Header  |  1992-11-19  |  12KB  |  454 lines

  1. /*
  2. Copyright (c) 1992, Trevor Smigiel.  All rights reserved.
  3.  
  4. (I hope Commodore doesn't mind that I borrowed their copyright notice.)
  5.  
  6. The source and executable code of this program may only be distributed in free
  7. electronic form, via bulletin board or as part of a fully non-commercial and
  8. freely redistributable diskette.  Both the source and executable code (including
  9. comments) must be included, without modification, in any copy.  This example may
  10. not be published in printed form or distributed with any commercial product.
  11.  
  12. This program is provided "as-is" and is subject to change; no warranties are
  13. made.  All use is at your own risk.  No liability or responsibility is assumed.
  14.  
  15. */
  16.  
  17. #include <exec/types.h>
  18. #include <intuition/intuition.h>
  19. #include <intuition/gadgetclass.h>
  20. #include <intuition/icclass.h>
  21. #include <clib/macros.h>
  22. #include <stdio.h>
  23. #include "tetris.h"
  24. #include "con_input.h"
  25. /* */
  26. #include <proto/exec.h>
  27. #include <proto/dos.h>
  28. #include <proto/intuition.h>
  29.  
  30. #include "Tetris_protos.h"
  31. #include "TetrisImages_protos.h"
  32.  
  33. UBYTE *vers = "$VER: Tetris 1.0";
  34.  
  35. void KeyTask(void);
  36. void JoyTask(void);
  37.  
  38. #define MAX_PLAYERS 3
  39. #define STACK_SIZE 10000L
  40.  
  41. void (*TaskEntries[])(void) = { KeyTask, KeyTask, KeyTask, JoyTask };
  42.  
  43. /* Each switch on a joystick corrosponds to a bit in cd_State */
  44. /* The index of the character in the key string, is the same bit in cd_State */
  45. /* bit   6  5  4  3  2  1  0 */
  46. /*      mb rb lb  u  d  l  r */
  47. char *ControlKeys[] = {
  48.     "\x22\x20\x21\x10\x11", /* and the same for these */
  49.     "\x28\x26\x27\x16\x17", /* ditto */
  50.     "\x2f\x2d\x2e\x1e\x3e", /* These keys are only good for Tetris */
  51.     NULL, /* joystick */
  52. };
  53.  
  54. char *ControlUsage[] = {
  55.     "keyboard:   w - rotate, a - left, s - down, d - right.",
  56.     "keyboard:   i - rotate, j - left, k - down, l - right.",
  57.     "numberpad:  8 - rotate, 4 - left, 5 - down, 6 - right.",
  58.     "joystick:   up/button - rotate, left - left, down - down, right - right.",
  59. };
  60.  
  61. struct ControlData Controls[MAX_PLAYERS];
  62.  
  63. struct Screen       *Screen;
  64. struct Window       *Window;
  65. struct Gadget       *Gadgets;
  66. struct MsgPort      *tetris_MsgPort;
  67. struct MsgPort      *timer_MsgPort;
  68. struct timerequest  *timer_IORequest;
  69. struct MinList Boards    = {(struct MinNode *)&Boards.mlh_Tail, NULL, (struct MinNode *)&Boards};
  70. WORD heights[2];
  71.  
  72. WORD PWidth = 0;
  73. WORD PHeight = 0;
  74. WORD NumPlayers = 0;
  75. WORD Players  = 1;
  76. WORD Level    = 0;
  77. WORD BSize    = 8;
  78. WORD XSize    = 16;
  79. WORD YSize    = 16;
  80. WORD Depth    = 2;
  81. WORD NoWaitLevel = 0;
  82. WORD Flags = 0;
  83.  
  84. #define GFLG_QUIT 0x0001
  85.  
  86. void 
  87. event_handler(void)
  88. {
  89.     struct TBoard *board;
  90.     ULONG signals, signaled;
  91.     ULONG timer_signal, window_signal, tetris_signal;
  92.     WORD paused = 0;
  93.     int i, gameover, nextlevel;
  94.  
  95.     for (i = 0; i < Players; i++) {
  96.         if (Controls[i].cd_Task) {
  97.             board = Controls[i].cd_Board;
  98.             StartLevel(board, Level);
  99.         }
  100.     }
  101.  
  102.     tetris_signal = (1 << tetris_MsgPort->mp_SigBit);
  103.     timer_signal = (1 << timer_MsgPort->mp_SigBit);
  104.     window_signal = (1 << Window->UserPort->mp_SigBit);
  105.     signals = tetris_signal | timer_signal | window_signal | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F; 
  106.  
  107.     while (NumPlayers > 0) {
  108.         signaled = Wait(signals);
  109.  
  110.         if (signaled & SIGBREAKF_CTRL_C)
  111.             Flags |= GFLG_QUIT;
  112.  
  113.         if (signaled & SIGBREAKF_CTRL_F) { /* Child is done */
  114.             for (i = 0; i < Players; i++) {
  115.                 if ((Controls[i].cd_Task != NULL) && (Controls[i].cd_MsgPort == NULL)) {
  116.                     FreeBoard(Controls[i].cd_Board);
  117.                     DeleteTask(Controls[i].cd_Task);
  118.                     Controls[i].cd_Board = NULL;
  119.                     Controls[i].cd_Task  = NULL;
  120.                     NumPlayers--;
  121.                 }
  122.             }
  123.         }
  124.  
  125.         if (signaled & timer_signal) {
  126.             GetMsg(timer_MsgPort); /* There is only one message -- timer_IORequest */
  127.             timer_IORequest->tr_time.tv_secs  = 0;
  128.             timer_IORequest->tr_time.tv_micro = UPDATE_TIME;
  129.             SendIO((struct IORequest *)timer_IORequest);
  130.             for (i = 0; i < Players; i++) {
  131.                 if (Controls[i].cd_Task)
  132.                     UpdateTetris(Controls[i].cd_Board);
  133.             }
  134.         }
  135.  
  136.         if (signaled & tetris_signal) {
  137.             struct ControlMsg *cmsg;
  138.             while (cmsg = (struct ControlMsg *)GetMsg(tetris_MsgPort)) {
  139.                 if ((!paused) && (board = cmsg->cm_CData->cd_Board)) {
  140.                     int state = cmsg->cm_State;
  141.                     if (state & 1)
  142.                         MoveTetris(board, COMMAND_RIGHT);
  143.                     else if (state & 2)
  144.                         MoveTetris(board, COMMAND_LEFT);
  145.                     if (state & 4)
  146.                         MoveTetris(board, COMMAND_DOWN);
  147.                     else if (state & 8)
  148.                         MoveTetris(board, COMMAND_ROTATE); /* Two rotates to accomodate joysticks */
  149.                     if (state & 0x70) /* Any button */
  150.                         MoveTetris(board, COMMAND_ROTATE);
  151.                 }
  152.                 ReplyMsg((struct Message *)cmsg);
  153.             }
  154.         }
  155.  
  156.         if (signaled & window_signal) {
  157.             struct IntuiMessage *msg;
  158.             while (msg = (struct IntuiMessage *)GetMsg(Window->UserPort)) {
  159.  
  160.                 switch (msg->Class) {
  161.                 case IDCMP_CHANGEWINDOW:
  162.                 case IDCMP_ACTIVEWINDOW:
  163.                     if (Window->Height != heights[paused]) {
  164.                         if (paused) {
  165.                             paused = 0;
  166.                             for (i = 0; i < Players; i++) {
  167.                                 if (Controls[i].cd_Task)
  168.                                     Signal(Controls[i].cd_Task, SIGBREAKF_CTRL_E);
  169.                             }
  170.                             
  171.                             SetWindowTitles(Window, "Tetris", "Tetris");
  172.                             if (CheckIO((struct IORequest *) timer_IORequest)) {
  173.                                 timer_IORequest->tr_time.tv_secs  = 0;
  174.                                 timer_IORequest->tr_time.tv_micro = UPDATE_TIME;
  175.                                 SendIO((struct IORequest *)timer_IORequest);
  176.                             }
  177.                         } else {
  178.                 case IDCMP_INACTIVEWINDOW:
  179.                             paused = 1;
  180.                             for (i = 0; i < Players; i++) {
  181.                                 if (Controls[i].cd_Task)
  182.                                     Signal(Controls[i].cd_Task, SIGBREAKF_CTRL_D);
  183.                             }
  184.                             SetWindowTitles(Window, "Paused", "Tetris");
  185.                             if (!CheckIO((struct IORequest *) timer_IORequest)) {
  186.                                 AbortIO((struct IORequest *) timer_IORequest);
  187.                                 WaitIO((struct IORequest *) timer_IORequest);
  188.                                 SetSignal(0, timer_signal);
  189.                             }
  190.                         }
  191.                     }
  192.                     break;
  193.                 case IDCMP_REFRESHWINDOW:
  194.                     BeginRefresh(Window);
  195.                     for (i = 0; i < Players; i++) {
  196.                         if (Controls[i].cd_Task)
  197.                             DrawBoard(Controls[i].cd_Board);
  198.                     }
  199.                     EndRefresh(Window, TRUE);
  200.                     break;
  201.  
  202.                 case IDCMP_CLOSEWINDOW:
  203.                     Flags |= GFLG_QUIT;
  204.                     break;
  205.  
  206.                 default:
  207.                     break;
  208.                 }
  209.                 ReplyMsg((struct Message *)msg);
  210.             }
  211.         }
  212.  
  213.         if (Flags & GFLG_QUIT) {
  214.             for (i = 0; i < Players; i++) {
  215.                 if (Controls[i].cd_Task)
  216.                     Signal(Controls[i].cd_Task, SIGBREAKF_CTRL_C);
  217.             }
  218.             paused = 1;
  219.             if (!CheckIO((struct IORequest *) timer_IORequest)) {
  220.                 AbortIO((struct IORequest *) timer_IORequest);
  221.                 WaitIO((struct IORequest *) timer_IORequest);
  222.                 SetSignal(0, timer_signal);
  223.             }
  224.         }
  225.  
  226.         if (!paused) {
  227.             nextlevel = gameover = 0;
  228.             for (i = 0; i < Players; i++) {
  229.                 if (Controls[i].cd_Task) {
  230.                     board = Controls[i].cd_Board;
  231.                     if (board->flags & TETF_GAMEOVER)
  232.                         gameover++;
  233.                     else if (board->flags & TETF_NEXTLEVEL)
  234.                         nextlevel++;
  235.                 }
  236.             }
  237.             if ((NoWaitLevel) || (nextlevel == (i - gameover))) {
  238.                 for (i = 0; i < Players; i++) {
  239.                     if (Controls[i].cd_Task) {
  240.                         board = Controls[i].cd_Board;
  241.                         if (board->flags & TETF_NEXTLEVEL) {
  242.                             StartLevel(board, board->clevel + 1);
  243.                         }
  244.                     }
  245.                 }
  246.             }
  247.         } 
  248.  
  249.     } /* end Wait Loop */
  250. }
  251.  
  252. #define next event_handler
  253.  
  254. BOOL
  255. StartOfGame(void)
  256. {
  257.     struct ControlData *c;
  258.     int x, y;
  259.     struct Task *ThisTask = FindTask(NULL);
  260.  
  261.     for (c = &Controls[0], NumPlayers = 0; NumPlayers < Players; c++, NumPlayers++) {
  262.         c->cd_Board = NULL;
  263.         c->cd_Task = CreateTask("Tetris_ConTask", 0, TaskEntries[NumPlayers], STACK_SIZE);
  264.         if (!c->cd_Task) break;
  265.         c->cd_Board = NewBoard(Window->RPort, Window->BorderLeft + BSize + (PWidth + BSize * 2) * NumPlayers, heights[1]);
  266.         if (!c->cd_Board) {
  267.             DeleteTask(c->cd_Task);
  268.             c->cd_Task = NULL;
  269.             break;
  270.         }
  271.         printf("Player %d uses %s\n", NumPlayers, ControlUsage[NumPlayers]);
  272.         c->cd_Parent  = ThisTask;
  273.         c->cd_MsgPort = tetris_MsgPort;
  274.         c->cd_State   = 0; 
  275.         c->cd_Keys    = ControlKeys[NumPlayers];
  276.         c->cd_Task->tc_UserData = c;
  277.         Signal(c->cd_Task, SIGBREAKF_CTRL_F); /* Signal task, the data is ready */
  278.     }
  279.     if (NumPlayers != Players) {
  280.         x = NumPlayers * (PWidth + BSize * 2) + Screen->WBorLeft + Screen->WBorRight;
  281.         y = heights[0] = PHeight + Screen->WBorBottom + heights[1] + BSize;
  282.         ChangeWindowBox(Window, (Screen->Width - x) / 2, (Screen->Height - y) / 2, x, y);
  283.     }
  284.     return NumPlayers;
  285. }
  286.  
  287. void 
  288. EndOfGame(void)
  289. {
  290.     int i;
  291.     for (i = 0; i < NumPlayers; i++) { /* Make sure everything is freed */
  292.         if (Controls[i].cd_Board) {
  293.             printf("FreeBoard - this shouldn't have happened.\n");
  294.             FreeBoard(Controls[i].cd_Board);
  295.         }
  296.         if (Controls[i].cd_Task) {
  297.             printf("DeleteTask - this shouldn't have happened.\n");
  298.             DeleteTask(Controls[i].cd_Task);
  299.         }
  300.     }
  301. }
  302.  
  303. void
  304. tetris(void)
  305. {
  306.     if (InitTetrisImages(Screen->BitMap.Depth, XSize, YSize)) {
  307.         if (StartOfGame()) { /* Add Players */
  308.             next();
  309.             EndOfGame();
  310.         }
  311.         FreeTetrisImages(Screen->BitMap.Depth, XSize, YSize);
  312.     }
  313. }
  314.  
  315. #undef next
  316. #define next tetris
  317.  
  318. struct Window *
  319. tetris_window(void)
  320. {
  321.     struct Window *w;
  322.     WORD zoom[4];
  323.  
  324.     heights[1] = Screen->WBorTop + Screen->Font->ta_YSize + 1 + YSize * 4;
  325.     heights[0] = PHeight + Screen->WBorBottom + heights[1] + BSize;
  326.     zoom[3] = heights[1];
  327.     zoom[2] = Players * (PWidth + (BSize * 2)) + Screen->WBorLeft + Screen->WBorRight;
  328.     zoom[1] = (Screen->Height - heights[0]) / 2;
  329.     zoom[0] = (Screen->Width - zoom[2]) / 2;
  330.     w = OpenWindowTags(NULL,
  331.         WA_Title, "Tetris",
  332.         WA_ScreenTitle, "Tetris",
  333.         WA_Left, zoom[0],
  334.         WA_Top,  zoom[1],
  335.         WA_Width,zoom[2],
  336.         WA_Height,  heights[0],
  337.         WA_Zoom, zoom,
  338.         WA_Gadgets, Gadgets,
  339.         WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE,// | WFLG_GIMMEZEROZERO,
  340.         WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_IDCMPUPDATE | IDCMP_CHANGEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_REFRESHWINDOW,
  341.         TAG_DONE
  342.     );
  343.     return w;
  344. }
  345.  
  346. void
  347. window(void)
  348. {
  349.     Window = tetris_window();
  350.     if (Window) {
  351.         next();
  352.         CloseWindow(Window);
  353.     }
  354. }
  355.  
  356. #undef next
  357. #define next window
  358.  
  359. void
  360. screen(void)
  361. {
  362.     Screen = LockPubScreen(NULL);
  363.     if (Screen) {
  364.         next();
  365.         UnlockPubScreen(NULL, Screen);
  366.     }
  367. }
  368.  
  369. #undef next
  370. #define next screen
  371.  
  372. void 
  373. timer(void)
  374. {
  375.     timer_MsgPort = CreateMsgPort();
  376.     if (timer_MsgPort) {
  377.         timer_IORequest = (struct timerequest *)CreateIORequest(timer_MsgPort, sizeof(struct timerequest));
  378.         if (timer_IORequest) {
  379.             if (!OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_IORequest, 0L)) {
  380.  
  381.                 timer_IORequest->tr_node.io_Command = TR_ADDREQUEST;
  382.                 timer_IORequest->tr_time.tv_secs  = 0;
  383.                 timer_IORequest->tr_time.tv_micro = UPDATE_TIME;
  384.                 SendIO((struct IORequest *)timer_IORequest);
  385.  
  386.                 next();
  387.  
  388.                 if (!CheckIO((struct IORequest *) timer_IORequest)) {
  389.                     AbortIO((struct IORequest *) timer_IORequest);
  390.                     WaitIO((struct IORequest *) timer_IORequest);
  391.                 }
  392.  
  393.                 CloseDevice((struct IORequest *) timer_IORequest);
  394.             } else printf("No timer.device!\n");
  395.  
  396.             DeleteIORequest((struct IORequest *) timer_IORequest);
  397.         } else printf("No timer io request!\n");
  398.         DeleteMsgPort(timer_MsgPort);
  399.     } else printf("No timer msg port!\n");
  400. }
  401.  
  402. #undef next
  403. #define next timer
  404.  
  405. void
  406. msgport(void)
  407. {
  408.     tetris_MsgPort = CreateMsgPort();
  409.     if (tetris_MsgPort) {
  410.         tetris_MsgPort->mp_Node.ln_Name = TETRIS_PORT;
  411.         next();
  412.         DeleteMsgPort(tetris_MsgPort);
  413.     } else printf("No player msg port!\n");
  414. }
  415.  
  416. #undef next
  417. #define next msgport
  418.  
  419. BOOL
  420. ParseArgs(void)
  421. {
  422.     struct RDArgs *RDArgs;
  423.     char Template[] = "PLAYERS/N,LEVEL/N,DEPTH/N,XSIZE/N,YSIZE/N,BORDER/N,NOWAIT/S";
  424.     LONG Args[] = {0, 0, 0, 0, 0, 0, 0};
  425.  
  426.     RDArgs = ReadArgs(Template, Args, NULL);
  427.     if (RDArgs) {
  428.         if (Args[0]) { Players = *(LONG *)Args[0]; if (Players > MAX_PLAYERS) Players = MAX_PLAYERS; }
  429.         if (Args[1]) Level = *(LONG *)Args[1];
  430.         if (Args[2]) Depth = *(LONG *)Args[2];
  431.         if (Args[3]) XSize = *(LONG *)Args[3];
  432.         if (Args[4]) YSize = *(LONG *)Args[4];
  433.         if (Args[5]) BSize = *(LONG *)Args[5];
  434.         NoWaitLevel = Args[6];
  435.         PWidth  = (PFWIDTH  * XSize);
  436.         PHeight = (PFHEIGHT * YSize);
  437.         FreeArgs(RDArgs);
  438.         return TRUE;
  439.     }
  440.     return FALSE;
  441. }
  442.  
  443. int 
  444. main(void)
  445. {
  446.     printf("Tetris version 1.0\nCopyright (C) 1992 Trevor Smigiel.\n");
  447.     if (ParseArgs()) {
  448.         if(!(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C))
  449.             next();
  450.     } else PrintFault(IoErr(), "ReadArgs");
  451.     return 0;
  452. }
  453.  
  454.